package org.apache.ibatis.ibator.plugins;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.ibator.api.GeneratedJavaFile;
import org.apache.ibatis.ibator.api.GeneratedXmlFile;
import org.apache.ibatis.ibator.api.IbatorPluginAdapter;
import org.apache.ibatis.ibator.api.IntrospectedTable;
import org.apache.ibatis.ibator.api.dom.java.Field;
import org.apache.ibatis.ibator.api.dom.java.FullyQualifiedJavaType;
import org.apache.ibatis.ibator.api.dom.java.Interface;
import org.apache.ibatis.ibator.api.dom.java.JavaVisibility;
import org.apache.ibatis.ibator.api.dom.java.Method;
import org.apache.ibatis.ibator.api.dom.java.Parameter;
import org.apache.ibatis.ibator.api.dom.java.TopLevelClass;
import org.apache.ibatis.ibator.api.dom.xml.Attribute;
import org.apache.ibatis.ibator.api.dom.xml.Document;
import org.apache.ibatis.ibator.api.dom.xml.Element;
import org.apache.ibatis.ibator.api.dom.xml.XmlElement;
import org.apache.ibatis.ibator.generator.XmlConstants;
import org.apache.ibatis.ibator.generator.ibatis2.sqlmap.elements.AbstractXmlElementGenerator;
import org.apache.ibatis.ibator.generator.ibatis2.sqlmap.elements.DynamicSqlGenerator;
import org.apache.ibatis.ibator.generator.ibatis2.sqlmap.elements.ExampleWhereClauseElementGenerator;
import org.apache.ibatis.ibator.generator.ibatis2.sqlmap.elements.MysqlPaginationLimitGenerator;
import org.apache.ibatis.ibator.generator.ibatis2.sqlmap.elements.OraclePaginationHeadGenerator;
import org.apache.ibatis.ibator.generator.ibatis2.sqlmap.elements.OraclePaginationTailGenerator;
import org.apache.ibatis.ibator.generator.ibatis3.pagination.Ibatis3PaginationGenerator;
import org.apache.ibatis.ibator.generator.ibatis3.pagination.javamapper.JavaMapperPaginationGenerator;
import org.apache.ibatis.ibator.internal.util.StringUtility;

/**
 * 分页插件
 * 
 * @author liwb 2016年1月27日 下午4:00:10
 */
public class PaginationPlugin extends IbatorPluginAdapter {
    /** 是否分页,仅对ibatis3* */
    private String generatedPageBean;
    /** 数据库类型 */
    private String databaseType;
    private IntrospectedTable introspectedTable;

    @Override
    public boolean validate(List<String> warnings) {
        databaseType = properties.getProperty("databaseType");
        generatedPageBean = properties.getProperty("generatedPageBean");
        generatedPageBean = generatedPageBean == null ? "false"
                : generatedPageBean;
        boolean valid = StringUtility.stringHasValue(databaseType)
                && StringUtility.stringHasValue(generatedPageBean);

        return valid;
    }

    @Override
    public boolean sqlMapDocumentGenerated(Document document,
            IntrospectedTable introspectedTable) {
        XmlElement element = document.getRootElement();
        if ("Ibatis3".equals(ibatorContext.getTargetRuntime())) {
            if ("oracle".equalsIgnoreCase(databaseType)) {

            } else if ("mysql".equalsIgnoreCase(databaseType)) {
                new Ibatis3PaginationGenerator().xmlMySqlGenerator(
                        ibatorContext, introspectedTable, element);
            }
        } else {
            if ("oracle".equalsIgnoreCase(databaseType)) {

            } else if ("mysql".equalsIgnoreCase(databaseType)) {
                List<Element> list = element.getElements();
                list.remove(1);
            }
        }

        return super.sqlMapDocumentGenerated(document, introspectedTable);
    }

    public boolean daoInterfaceGenerated(Interface interfaze,
            IntrospectedTable introspectedTable) {
        if ("Ibatis3".equals(ibatorContext.getTargetRuntime())) {
            new JavaMapperPaginationGenerator(interfaze, introspectedTable,
                    ibatorContext).generator();
        }
        return super.daoInterfaceGenerated(interfaze, introspectedTable);
    }

    @Override
    public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(
            XmlElement element, IntrospectedTable introspectedTable) {
        if ("Ibatis3".equals(ibatorContext.getTargetRuntime())) {

        } else {
            if (databaseType.contains("oracle")) {
                XmlElement oracleHeadIncludeElement = new XmlElement("include");
                oracleHeadIncludeElement
                        .addAttribute(new Attribute(
                                "refid",
                                XmlConstants.COMMON
                                        + "."
                                        + OraclePaginationHeadGenerator.ORACLE_PAGINATION_HEAD));
                element.addElement(0, oracleHeadIncludeElement);

                XmlElement oracleTailIncludeElement = new XmlElement("include");
                oracleTailIncludeElement
                        .addAttribute(new Attribute(
                                "refid",
                                XmlConstants.COMMON
                                        + "."
                                        + OraclePaginationTailGenerator.ORACLE_PAGINATION_TAIL));
                element.addElement(element.getElements().size(),
                        oracleTailIncludeElement);
            } else if (databaseType.contains("mysql")) {
                XmlElement mysqlLimitIncludeElement = new XmlElement("include");
                mysqlLimitIncludeElement
                        .addAttribute(new Attribute(
                                "refid",
                                XmlConstants.COMMON
                                        + "."
                                        + MysqlPaginationLimitGenerator.MYSQL_PAGINATION_LIMIT));
                element.addElement(element.getElements().size(),
                        mysqlLimitIncludeElement);
            }
        }
        return super.sqlMapExampleWhereClauseElementGenerated(element,
                introspectedTable);
    }

    @Override
    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(
            XmlElement element, IntrospectedTable introspectedTable) {
        if ("Ibatis3".equals(ibatorContext.getTargetRuntime())) {

        } else {
            if (databaseType.contains("oracle")) {
                XmlElement oracleHeadIncludeElement = new XmlElement("include");
                oracleHeadIncludeElement
                        .addAttribute(new Attribute(
                                "refid",
                                XmlConstants.COMMON
                                        + "."
                                        + OraclePaginationHeadGenerator.ORACLE_PAGINATION_HEAD));
                element.addElement(0, oracleHeadIncludeElement);

                XmlElement oracleTailIncludeElement = new XmlElement("include");
                oracleTailIncludeElement
                        .addAttribute(new Attribute(
                                "refid",
                                XmlConstants.COMMON
                                        + "."
                                        + OraclePaginationTailGenerator.ORACLE_PAGINATION_TAIL));
                element.addElement(element.getElements().size(),
                        oracleTailIncludeElement);
            } else if (databaseType.contains("mysql")) {
                XmlElement mysqlLimitIncludeElement = new XmlElement("include");
                mysqlLimitIncludeElement
                        .addAttribute(new Attribute(
                                "refid",
                                XmlConstants.COMMON
                                        + "."
                                        + MysqlPaginationLimitGenerator.MYSQL_PAGINATION_LIMIT));
                element.addElement(element.getElements().size(),
                        mysqlLimitIncludeElement);
            }
        }

        return super.sqlMapSelectByExampleWithoutBLOBsElementGenerated(element,
                introspectedTable);
    }

    @Override
    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
            IntrospectedTable introspectedTable) {
        if ("Ibatis3".equals(ibatorContext.getTargetRuntime())) {

        } else {
            if (databaseType.contains("oracle")) {
                // add field, getter, setter for oracleStart clause
                Field field = new Field();
                field.setVisibility(JavaVisibility.PRIVATE);
                field.setType(FullyQualifiedJavaType.getInteger());
                field.setName("oracleStart"); //$NON-NLS-1$
                topLevelClass.addField(field);

                Method method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setName("setOracleStart"); //$NON-NLS-1$
                method.addParameter(new Parameter(FullyQualifiedJavaType
                        .getInteger(), "oracleStart")); //$NON-NLS-1$
                method.addBodyLine("this.oracleStart = oracleStart;"); //$NON-NLS-1$
                addSetterComment(method, "ffff", "oracleStart");
                topLevelClass.addMethod(method);

                method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setReturnType(FullyQualifiedJavaType.getInteger());
                method.setName("getOracleStart"); //$NON-NLS-1$
                method.addBodyLine("return oracleStart;"); //$NON-NLS-1$
                topLevelClass.addMethod(method);
                // add field, getter, setter for oracleEnd clause
                field = new Field();
                field.setVisibility(JavaVisibility.PRIVATE);
                field.setType(FullyQualifiedJavaType.getInteger());
                field.setName("oracleEnd"); //$NON-NLS-1$
                topLevelClass.addField(field);

                method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setName("setOracleEnd"); //$NON-NLS-1$
                method.addParameter(new Parameter(FullyQualifiedJavaType
                        .getInteger(), "oracleEnd")); //$NON-NLS-1$
                method.addBodyLine("this.oracleEnd = oracleEnd;"); //$NON-NLS-1$
                addSetterComment(method, "sssss", "oracleEnd");
                topLevelClass.addMethod(method);

                method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setReturnType(FullyQualifiedJavaType.getInteger());
                method.setName("getOracleEnd"); //$NON-NLS-1$
                method.addBodyLine("return oracleEnd;"); //$NON-NLS-1$
                topLevelClass.addMethod(method);

            } else if (databaseType.contains("mysql")) {
                // add field, getter, setter for mysqlOffset clause
                Field field = new Field();
                field.setVisibility(JavaVisibility.PRIVATE);
                field.setType(FullyQualifiedJavaType.getInteger());
                field.setName("mysqlOffset"); //$NON-NLS-1$
                topLevelClass.addField(field);

                Method method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setName("setMysqlOffset"); //$NON-NLS-1$
                method.addParameter(new Parameter(FullyQualifiedJavaType
                        .getInteger(), "mysqlOffset")); //$NON-NLS-1$
                method.addBodyLine("this.mysqlOffset = mysqlOffset;"); //$NON-NLS-1$
                addSetterComment(method,
                        "sss<br> mysqlOffset= 5,mysqlLength=10;  // sss6-15",
                        "mysqlOffset");
                topLevelClass.addMethod(method);

                method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setReturnType(FullyQualifiedJavaType.getInteger());
                method.setName("getMysqlOffset"); //$NON-NLS-1$
                method.addBodyLine("return mysqlOffset;"); //$NON-NLS-1$
                topLevelClass.addMethod(method);
                // add field, getter, setter for mysqlLength clause
                field = new Field();
                field.setVisibility(JavaVisibility.PRIVATE);
                field.setType(FullyQualifiedJavaType.getInteger());
                field.setName("mysqlLength"); //$NON-NLS-1$
                topLevelClass.addField(field);

                method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setName("setMysqlLength"); //$NON-NLS-1$
                method.addParameter(new Parameter(FullyQualifiedJavaType
                        .getInteger(), "mysqlLength")); //$NON-NLS-1$
                method.addBodyLine("this.mysqlLength = mysqlLength;"); //$NON-NLS-1$
                addSetterComment(method,
                        "ssss<br> mysqlOffset= 5,mysqlLength=10;  // ssss",
                        "mysqlLength");
                topLevelClass.addMethod(method);

                method = new Method();
                method.setVisibility(JavaVisibility.PUBLIC);
                method.setReturnType(FullyQualifiedJavaType.getInteger());
                method.setName("getMysqlLength"); //$NON-NLS-1$
                method.addBodyLine("return mysqlLength;"); //$NON-NLS-1$
                topLevelClass.addMethod(method);
            }
        }

        return super.modelExampleClassGenerated(topLevelClass,
                introspectedTable);
    }

    @Override
    public List<GeneratedXmlFile> contextGenerateAdditionalXmlFiles() {
        if ("Ibatis3".equals(ibatorContext.getTargetRuntime())) {
            return super.contextGenerateAdditionalXmlFiles();
        } else {
            Document document = new Document(
                    XmlConstants.IBATIS2_SQL_MAP_PUBLIC_ID,
                    XmlConstants.IBATIS2_SQL_MAP_SYSTEM_ID);
            XmlElement answer = new XmlElement("sqlMap"); //$NON-NLS-1$
            document.setRootElement(answer);
            answer.addAttribute(new Attribute("namespace", //$NON-NLS-1$
                    XmlConstants.COMMON));

            AbstractXmlElementGenerator elementGenerator = new ExampleWhereClauseElementGenerator();
            elementGenerator.setIbatorContext(ibatorContext);
            elementGenerator.setIntrospectedTable(introspectedTable);
            elementGenerator.addElements(answer);

            if (databaseType.contains("oracle")) {
                AbstractXmlElementGenerator oraclePaginationHeadGenerator = new OraclePaginationHeadGenerator();
                oraclePaginationHeadGenerator.setIbatorContext(ibatorContext);
                oraclePaginationHeadGenerator.addElements(answer);
                AbstractXmlElementGenerator oraclePaginationTailGenerator = new OraclePaginationTailGenerator();
                oraclePaginationTailGenerator.setIbatorContext(ibatorContext);
                oraclePaginationTailGenerator.addElements(answer);
            } else if (databaseType.contains("mysql")) {
                AbstractXmlElementGenerator mysqlPaginationLimitGenerator = new MysqlPaginationLimitGenerator();
                mysqlPaginationLimitGenerator.setIbatorContext(ibatorContext);
                mysqlPaginationLimitGenerator.addElements(answer);
            }
            elementGenerator = new DynamicSqlGenerator();
            elementGenerator.addElements(answer);

            GeneratedXmlFile gxf = new GeneratedXmlFile(document,
                    properties.getProperty(
                            "fileName", XmlConstants.COMMON + "_SqlMap.xml"), //$NON-NLS-1$ //$NON-NLS-2$
                    ibatorContext.getSqlMapGeneratorConfiguration()
                            .getTargetPackage(), //$NON-NLS-1$
                    ibatorContext.getSqlMapGeneratorConfiguration()
                            .getTargetProject(), //$NON-NLS-1$
                    false);

            List<GeneratedXmlFile> files = new ArrayList<GeneratedXmlFile>(1);
            files.add(gxf);

            return files;
        }
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles() {
        if (StringUtility.stringHasValue(generatedPageBean)
                && "true".equalsIgnoreCase(generatedPageBean)) {
            List<GeneratedJavaFile> files = new ArrayList<GeneratedJavaFile>();
            TopLevelClass topLevelClass = new TopLevelClass(
                    new FullyQualifiedJavaType(ibatorContext
                            .getJavaModelGeneratorConfiguration()
                            .getTargetPackage()
                            + ".PageBean"));
            topLevelClass.addAnnotation("// 分页实体");
            topLevelClass.setVisibility(JavaVisibility.PUBLIC);
            addField(topLevelClass);
            addMethod(topLevelClass);
            GeneratedJavaFile file = new GeneratedJavaFile(topLevelClass,
                    ibatorContext.getJavaModelGeneratorConfiguration()
                            .getTargetProject());
            files.add(file);
            return files;
        } else {
            return null;
        }
    }

    @Override
    public void initialized(IntrospectedTable introspectedTable) {
        this.introspectedTable = introspectedTable;
    }

    /**
     * 添加字段
     *
     * @param topLevelClass
     */
    protected void addField(TopLevelClass topLevelClass) {
        Field currentPageField = new Field();
        currentPageField.setName("currentPage");
        currentPageField.addAnnotation("// 当前页");
        currentPageField.setType(FullyQualifiedJavaType.getInteger());
        currentPageField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(currentPageField);

        Field totalField = new Field();
        totalField.setName("total");
        totalField.addAnnotation("// 数据总条数");
        totalField.setType(FullyQualifiedJavaType.getInteger());
        totalField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(totalField);

        Field pageSizeField = new Field();
        pageSizeField.setName("pageSize");
        pageSizeField.addAnnotation("// 每页显示的数据条数");
        pageSizeField.setType(FullyQualifiedJavaType.getInteger());
        pageSizeField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(pageSizeField);

        Field listField = new Field();
        listField.setName("list");
        listField.addAnnotation("// 数据集合");
        FullyQualifiedJavaType listType = new FullyQualifiedJavaType(
                "java.util.List");
        topLevelClass.addImportedType(listType);
        listField.setType(listType);
        listField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(listField);

        Field orderField = new Field();
        orderField.setName("order");
        orderField.addAnnotation("// 排序字段");
        orderField.setType(FullyQualifiedJavaType.getStringInstance());
        orderField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(orderField);

        Field ascOrDescField = new Field();
        ascOrDescField.setName("ascOrDesc");
        ascOrDescField.addAnnotation("// 升序或降序标识");
        ascOrDescField.setType(FullyQualifiedJavaType.getStringInstance());
        ascOrDescField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(ascOrDescField);

        Field startNumField = new Field();
        startNumField.setName("startNum");
        startNumField.addAnnotation("// 开始数据起始位置");
        startNumField.setType(FullyQualifiedJavaType.getInteger());
        startNumField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(startNumField);

        Field endNumField = new Field();
        endNumField.setName("endNum");
        endNumField.addAnnotation("// 结束数据位置");
        endNumField.setType(FullyQualifiedJavaType.getInteger());
        endNumField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(endNumField);

        Field groupByField = new Field();
        groupByField.setName("groupBy");
        groupByField.addAnnotation("// 分组排序");
        groupByField.setType(FullyQualifiedJavaType.getStringInstance());
        groupByField.setVisibility(JavaVisibility.PRIVATE);
        topLevelClass.addField(groupByField);
    }

    /**
     * 添加方法
     */
    protected void addMethod(TopLevelClass topLevelClass) {
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getCurrentPage");
        method.setReturnType(FullyQualifiedJavaType.getInteger());
        method.addBodyLine("return currentPage;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setCurrentPage");
        method.addParameter(new Parameter(FullyQualifiedJavaType.getInteger(),
                "currentPage"));
        method.addBodyLine("this.currentPage = currentPage;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getTotal");
        method.setReturnType(FullyQualifiedJavaType.getInteger());
        method.addBodyLine("return total;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setTotal");
        method.addParameter(new Parameter(FullyQualifiedJavaType.getInteger(),
                "total"));
        method.addBodyLine("this.total = total;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getPageSize");
        method.setReturnType(FullyQualifiedJavaType.getInteger());
        method.addBodyLine("return pageSize;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setPageSize");
        method.addParameter(new Parameter(FullyQualifiedJavaType.getInteger(),
                "pageSize"));
        method.addBodyLine("this.pageSize = pageSize;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        FullyQualifiedJavaType listType = new FullyQualifiedJavaType(
                "java.util.List");
        method.setName("getList");
        method.setReturnType(listType);
        method.addBodyLine("return list;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setList");
        method.addParameter(new Parameter(listType, "list"));
        method.addBodyLine("this.list = list;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getOrder");
        method.setReturnType(FullyQualifiedJavaType.getStringInstance());
        method.addBodyLine("return order;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setOrder");
        method.addParameter(new Parameter(FullyQualifiedJavaType
                .getStringInstance(), "order"));
        method.addBodyLine("this.order = order;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getAscOrDesc");
        method.setReturnType(FullyQualifiedJavaType.getStringInstance());
        method.addBodyLine("return ascOrDesc;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setAscOrDesc");
        method.addParameter(new Parameter(FullyQualifiedJavaType
                .getStringInstance(), "ascOrDesc"));
        method.addBodyLine("this.ascOrDesc = ascOrDesc;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getStartNum");
        method.setReturnType(FullyQualifiedJavaType.getInteger());
        method.addBodyLine("if (currentPage - 1 < 0) {");
        method.addBodyLine("    return currentPage;");
        method.addBodyLine("} else");
        method.addBodyLine("    return (currentPage - 1) * pageSize;");

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        topLevelClass.addImportedType(new FullyQualifiedJavaType(
                "net.sf.json.JSONArray"));
        method.setName("toJson");
        method.setReturnType(FullyQualifiedJavaType.getStringInstance());
        method.addBodyLine("StringBuilder b = new StringBuilder(\"{\\\"total\\\":\");");
        method.addBodyLine("b.append(total);");
        method.addBodyLine("b.append(\",\\\"rows\\\":\");");
        method.addBodyLine("JSONArray arr = new JSONArray();");
        method.addBodyLine("arr.addAll(list);");
        method.addBodyLine("b.append(arr.toString());");
        method.addBodyLine("b.append(\"}\");");
        method.addBodyLine("return b.toString();");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getEndNum");
        method.setReturnType(FullyQualifiedJavaType.getInteger());
        method.addBodyLine("return currentPage * pageSize;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setEndNum");
        method.addParameter(new Parameter(FullyQualifiedJavaType.getInteger(),
                "endNum"));
        method.addBodyLine("this.endNum = endNum;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("getGroupBy");
        method.setReturnType(FullyQualifiedJavaType.getStringInstance());
        method.addBodyLine("return groupBy;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setGroupBy");
        method.addParameter(new Parameter(FullyQualifiedJavaType
                .getStringInstance(), "groupBy"));
        method.addBodyLine("this.groupBy = groupBy;");
        topLevelClass.addMethod(method);

        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("setStartNum");
        method.addParameter(new Parameter(FullyQualifiedJavaType.getInteger(),
                "startNum"));
        method.addBodyLine("this.startNum = startNum;");
        topLevelClass.addMethod(method);
    }

    protected String toLowerCase(String tableName) {
        StringBuilder sb = new StringBuilder(tableName);
        sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
        return sb.toString();
    }

    protected String toUpperCase(String tableName) {
        StringBuilder sb = new StringBuilder(tableName);
        sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
        return sb.toString();
    }
}
